/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.epcs.model.dao.googleWrapper;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import com.epcs.model.dto.google.GoogleCalendar;
import com.epcs.model.dto.google.GoogleCalendarList;
import com.epcs.model.dto.google.GoogleDateTime;
import com.epcs.model.dto.google.GoogleEvent;
import com.epcs.model.dto.google.GoogleEventList;
import com.epcs.model.dto.google.GoogleToken;
import com.epcs.util.EpcsDateTimeUtil;

import org.apache.http.NameValuePair;
import org.apache.http.client.fluent.Form;
import org.joda.time.DateTime;

/**
 * 
 * @author Hà Hải Đăng
 */
public class GoogleAPIWrapper {

	private static String clientID = "264923769140-kt1m2vgmbru611ogtb6pf0r511o7ft36.apps.googleusercontent.com";
	private static String clientSecret = "xUg3UaLEfPhmUs8hDFHw4g8o";
	private String refreshToken = "";
	private String accessToken = "";
	private Gson gson;

	public GoogleAPIWrapper() {
		gson = new Gson();
	}

	public GoogleAPIWrapper(String refreshToken) {
		gson = new GsonBuilder().create();
		this.refreshToken = refreshToken;
		this.accessToken = getAccessToken(refreshToken);
	}

	public static String getAuthURL() {
		String authURL = "https://accounts.google.com/o/oauth2/auth?" + "scope=%s" + "&redirect_uri=%s"
				+ "&response_type=code" + "&client_id=%s" + "&access_type=offline" + "&approval_prompt=force";
		String scope = "https://www.googleapis.com/auth/calendar";
		String redirect_uri = "http://epcs.com:8080/EPCS/ProcessPermission.do";
		String finalAuthUrl = String.format(authURL, scope, redirect_uri, clientID);

		return finalAuthUrl;
	}

	public String getRefreshToken(String authorizedCode) {
		String url = "https://accounts.google.com/o/oauth2/token";

		Form myForm = Form.form();
		myForm.add("code", authorizedCode);
		myForm.add("client_id", clientID);
		myForm.add("client_secret", clientSecret);
		myForm.add("redirect_uri", "http://epcs.com:8080/EPCS/ProcessPermission.do");
		myForm.add("grant_type", "authorization_code");

		List<NameValuePair> form = myForm.build();
		String result = WebUtil.postResult(url, form);

		GoogleToken token = gson.fromJson(result, GoogleToken.class);
		return token.getRefresh_token();
	}

	public final String getAccessToken(String refreshToken) {
		String url = "https://accounts.google.com/o/oauth2/token";

		Form myForm = Form.form();
		myForm.add("client_id", clientID);
		myForm.add("refresh_token", refreshToken);
		myForm.add("client_secret", clientSecret);
		myForm.add("grant_type", "refresh_token");

		List<NameValuePair> form = myForm.build();
		String result = WebUtil.postResult(url, form);

		GoogleToken token = gson.fromJson(result, GoogleToken.class);
		return token.getAccess_token();
	}

	public String getAccessToken() {
		return this.accessToken;
	}

	public List<GoogleCalendar> getCalendarList() {
		String url = "https://www.googleapis.com/calendar/v3/users/me/calendarList";
		url += "?fields=items(id,summary,description)";
		String result = WebUtil.getResult(url, accessToken);

		GoogleCalendarList calendarList = gson.fromJson(result, GoogleCalendarList.class);

		if (calendarList != null) {
        	return calendarList.getItems();
        }
        
        return null;
	}

	public List<GoogleEvent> getEventList(String calendarId) {
		String url = "https://www.googleapis.com/calendar/v3/calendars/%s/events";

		url = String.format(url, calendarId);
		String result = WebUtil.getResult(url, accessToken);

		GoogleEventList eventList = gson.fromJson(result, GoogleEventList.class);

		if (eventList != null) {
        	return eventList.getItems();
        }
        
        return null;
	}

	/**
	 * Method chỉ thực hiện trong khoảng thời gian tối đa là 3 tháng. 
	 * EX: tháng 1 đến tháng 3. 
	 * Chưa validate trong khoảng 3 tháng. 
	 * Khuyên dùng null cho giá trị toMonth để tự động
	 * 
	 * @param calendarId
	 * @param fromMonth là tháng trong năm (EX: 1, 12)
	 * @param toMonth là tháng trong năm (EX: 1, 12)
	 * @param isCurrentYear
	 *            để xác định là load trong năm nay hay năm tiếp theo. Nếu isCurrentYear = true thì
	 *            sẽ load data trong năm hiện tại. Nếu isCurrentYear = false thì sẽ load data trong
	 *            năm (hiện tại + 1)
	 * @return
	 */
	public List<GoogleEvent> getEventList(String calendarId, String fromMonth, String toMonth, boolean isCurrentYear) {

		
		// NOTE: Outlook ko thể tìm lớn hơn 3 tháng
		String fromDateTime = "";
		String toDateTime = "";
		int yearOfData = EpcsDateTimeUtil.getCurrentYearInteger();
		
		if (!isCurrentYear){
			yearOfData = yearOfData + 1;
		}

		// nếu ko có fromMonth --> mặc định là current month
		if (fromMonth == null) {
			// set lại fromMonth vì chưa có
			fromMonth = EpcsDateTimeUtil.getCurrentMothString();
			// tạo param value truyền cho timeMin
			fromDateTime = (yearOfData + "-" + fromMonth + "-01T00:00:00Z");
		} else {
			// chuyển thành dạng 2 chữ số (nếu chưa là 2 chữ số)
			fromMonth = EpcsDateTimeUtil.covertTo2Digit(fromMonth);
			// tạo param value truyền cho timeMin
			fromDateTime = (yearOfData + "-" + fromMonth + "-01T00:00:00Z");

		}

		// nếu ko có toMonth --> mặc định là current month + 3 tháng (lấy trong thời gian 3 tháng);
		if (toMonth == null) {
			// toMonth co thể vượt qua 12 --> sang năm mới --> kiểm tra trường hợp > 12 tháng
			// nếu lớn hơn 12 tháng thì chỉ lấy data của trong năm, trường hợp đó bên ngoài xử sau
			int tempToMonth = Integer.parseInt(fromMonth) + 3;

			if (tempToMonth > 12) {
				int nextYear = yearOfData + 1;
				// set lại toMonth tới ngày đầu năm sau yyyy-01-01
				toMonth = "01";
				// tạo param value truyền cho timeMax
				toDateTime = (nextYear + "-" + toMonth + "-01T00:00:00Z");
			} else {
				// set lại toMonth = fromMonth + 3 vì chưa có
				toMonth = EpcsDateTimeUtil.covertTo2Digit(String.valueOf(Integer.parseInt(fromMonth) + 3));
				// tạo param value truyền cho timeMax
				toDateTime = (yearOfData + "-"  + toMonth + "-01T00:00:00Z");
			}

		} else {
			/*
			 * Người ta hay sử dụng from và to để chỉ KHOẢNG thời gian --> Nhưng với service thì
			 * from = current --> và to = from + khoảng thời gian vậy nếu from = tháng 4 mà tìm
			 * trong khoảng 3 tháng thì to = 2 + 3 = 7 --> phải công thêm 1 đơn vị cho 'to'
			 */

			int tempToMonth = Integer.parseInt(toMonth) + 1;

			// nếu cộng lại mà toMonth lớn hơn 12 thì --> sang năm mới --> tháng quay về 01 tháng
			if (tempToMonth > 12) {
				int nextYear = yearOfData + 1;
				// set lại toMonth tới ngày đầu năm sau yyyy-01-01
				toMonth = "01";
				// tạo param value truyền cho timeMax
				toDateTime = (nextYear + "-" + toMonth + "-01T00:00:00Z");

			} else {
				// cần update để validate toMonth nằm trong khoảng 3 tháng
				
				// chuyển thành dạng 2 chữ số (nếu chưa là 2 chữ số)
				toMonth = EpcsDateTimeUtil.covertTo2Digit(String.valueOf(tempToMonth));
				// tạo param value truyền cho timeMax
				toDateTime = (yearOfData + "-"  + toMonth + "-01T00:00:00Z");
			}
			

		}

		// String url =
		// "https://www.googleapis.com/calendar/v3/calendars/%s/events?updatedMin=%s&showDeleted=false&timeMin=%s&timeMax=%s";
		String url = "https://www.googleapis.com/calendar/v3/calendars/%s/events?timeMin=%s&timeMax=%s";

		url = String.format(url, calendarId, fromDateTime, toDateTime);
		String result = WebUtil.getResult(url, accessToken);

		GoogleEventList eventList = gson.fromJson(result, GoogleEventList.class);

		List<GoogleEvent> items = null;
		if (eventList != null) {
			items = eventList.getItems();
			for (int i = 0; i < items.size(); i++) {
				GoogleEvent item = items.get(i);
				item.setCalendar_id(calendarId);
			}
        }
        
		return items;
	}

	public GoogleCalendar insertCalendar(String calendarName, String description) {
		String url = "https://www.googleapis.com/calendar/v3/calendars";

		// tao mot calendar voi description
		GoogleCalendar calendar = new GoogleCalendar();
		calendar.setSummary(calendarName);
		calendar.setDescription(description);

		// chuyen calendar thanh Json
		String calendarGson = gson.toJson(calendar);

		// dua gson len server
		String result = WebUtil.postResult(url, accessToken, calendarGson);

		calendar = gson.fromJson(result, GoogleCalendar.class);
		return calendar;
	}

	public GoogleEvent insertEvent(String calendarId, String summary, String startDate, String endDate) {
		String url = "https://www.googleapis.com/calendar/v3/calendars/%s/events";
		url = String.format(url, calendarId);

		// tao mot event voi description
		GoogleEvent event = new GoogleEvent();
		event.setSummary(summary);
		GoogleDateTime start = new GoogleDateTime();
		start.setDateTime(startDate);
		GoogleDateTime end = new GoogleDateTime();
		end.setDateTime(startDate);
		event.setStart(start);
		event.setEnd(end);

		// chuyen event thanh Json
		gson = getDateTimeParserGson();
		String eventGson = gson.toJson(event);

		// dua gson len server
		String result = WebUtil.postResult(url, accessToken, eventGson);

		event = gson.fromJson(result, GoogleEvent.class);
		return event;
	}

	public GoogleEvent insertEvent(Object eventItem) {
		String url = "https://www.googleapis.com/calendar/v3/calendars/%s/events";

		if (eventItem instanceof GoogleEvent) {
			url = String.format(url, ((GoogleEvent) eventItem).getCalendar_id());
		}

		// chuyen event thanh Json
		String eventGson = gson.toJson(eventItem);

		// dua gson len server
		String result = WebUtil.postResult(url, accessToken, eventGson);

		return gson.fromJson(result, GoogleEvent.class);
	}

	public GoogleCalendar updateCalendar(Object calendarItem) {

		String url = "https://www.googleapis.com/calendar/v3/calendars/%s";
		if (calendarItem instanceof GoogleCalendar) {
			String calendarID = ((GoogleCalendar) calendarItem).getId();
			url = String.format(url, calendarID);
		}

		// chuyen event thanh Json
		String eventGson = gson.toJson(calendarItem);

		// dua gson len server
		String result = WebUtil.putResult(url, accessToken, eventGson);

		return gson.fromJson(result, GoogleCalendar.class);
	}

	public GoogleEvent updateEvent(Object eventItem) {
		String url = "https://www.googleapis.com/calendar/v3/calendars/%s/events/%s";

		if (eventItem instanceof GoogleEvent) {
			String calendarID = ((GoogleEvent) eventItem).getCalendar_id();
			String eventID = ((GoogleEvent) eventItem).getId();
			url = String.format(url, calendarID, eventID);
		}

		// chuyen event thanh Json
		String eventGson = gson.toJson(eventItem);

		// dua gson len server
		String result = WebUtil.putResult(url, accessToken, eventGson);
		GoogleEvent event = gson.fromJson(result, GoogleEvent.class);
		event.setCalendar_id(((GoogleEvent) eventItem).getCalendar_id());

		return event;
	}

	public GoogleEvent getEvent(String calendarId, String eventId) {
		String url = "https://www.googleapis.com/calendar/v3/calendars/%s/events/%s";
		url = String.format(url, calendarId, eventId);

		String result = WebUtil.getResult(url, accessToken);
		GoogleEvent event = gson.fromJson(result, GoogleEvent.class);
		event.setCalendar_id(calendarId);

		return event;
	}

	public void deleteEvent(String calendarId, String eventId) {
		String url = "https://www.googleapis.com/calendar/v3/calendars/%s/events/%s";
		url = String.format(url, calendarId, eventId);

		WebUtil.deleteResult(url, accessToken);
	}

	public void deleteCalendar(String calendarId) {
		String url = "https://www.googleapis.com/calendar/v3/calendars/%s";
		url = String.format(url, calendarId);

		WebUtil.deleteResult(url, accessToken);
	}

	private Gson getExposeOnlyGson() {
		return new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
	}

	private Gson getDateTimeParserGson() {
		return new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ss.000+07:00")
				.excludeFieldsWithoutExposeAnnotation().create();
	}
}
